const { Service } = require('egg')
const cheerio = require('cheerio')
const { tableToList } = require('../utils/tools')

/**
 * 根据输入的成绩字符串判断其状态。
 * @param {string} str 表示成绩的字符串，可以是数字或者文字。
 * @return {Array} 返回一个包含两个元素的数组。第一个元素是输入的成绩字符串，第二个元素是成绩的状态，
 *                  如果成绩是数字，则状态为'已获'（及格）或'已开未获'（不及格）；如果成绩是文字，则状态为'已获'（及格）或'已开未获'（不及格）。
 */
const gradeStatus = (str) => {
  if (/^\d+$/.test(str)) { // 如果输入的是数字
    return [str, (Number(str) >= 60) ? '已获' : '已开未获'] // 判断数字是否及格，及格则返回'已获'，否则返回'已开未获'
  }
  return [str, str === '不及格' ? '已开未获' : '已获'] // 如果输入的是文字，判断是否为'不及格'，是则返回'已开未获'，否则返回'已获'
}

/**
 * 根据入学年份、开设学期（1、2、3、...）获取学期
 * @param {number} year 年份
 * @param {number} sub 开设学期（1、2、3、...）
 * @return {string} 学期
 */
const getTerm = (year, sub) => {
  // year不是数字返回空
  if (Number.isNaN(sub)) return ''
  const t1 = Number(year) + Math.floor((Number(sub) - 1) / 2)
  const t2 = Number(year) + Math.floor((Number(sub) - 1) / 2) + 1
  return `${t1}-${t2}-${Number(sub) % 2 === 0 ? '2' : '1'}`
}

module.exports = class CreditService extends Service {
  /**
   * * 学分修读情况
   * @return {Array} *
   */
  async table() {
    const Cookie = this.ctx.state.Cookie

    const planUrl = `${this.ctx.state.baseUrl}/eams/myPlan.action?_=1715338198817` // 培养方案

    const scheduletUrl = `${this.ctx.state.baseUrl}/eams/myPlanCompl.action?_=1715338198819` // 学习过程情况

    const gradeUrl = `${this.ctx.state.baseUrl}/eams/teach/grade/course/person!historyCourseGrade.action?projectType=MAJOR` // 成绩

    const P1 = this.ctx.curl(planUrl, {
      method: 'GET',
      headers: {
        Cookie,
        'Content-Type': 'application/x-www-form-urlencoded',
        'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.88 Safari/537.36',
      },
      timeout: 10000,
    })
    const P2 = this.ctx.curl(scheduletUrl, {
      method: 'GET',
      headers: {
        Cookie,
        'Content-Type': 'application/x-www-form-urlencoded',
        'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.88 Safari/537.36',
      },
      timeout: 10000,
    })
    const P3 = this.ctx.curl(gradeUrl, {
      method: 'POST',
      data: {
        kksj: '',
        kcxz: '',
        kcmc: '',
        xsfs: 'all',
      },
      headers: {
        Cookie,
        'Content-Type': 'application/x-www-form-urlencoded',
        'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.88 Safari/537.36',
      },
      timeout: 10000,
    })

    const [R1, R2, R3] = await Promise.all([P1, P2, P3])
    if (R1.status === 200 && R2.status === 200 && R3.status === 200) {
      try {
        /* 获取课程应修分数 */
        const needTable = tableToList(R1.data.toString(), '#planInfoTable1688')
        // for (let i = 0; i < needTable.length; i++) {
        //   console.log('needTable[i].length', needTable[i].length)
        // }
        // console.log('R1.data.toString()', R1.data.toString())
        const need = { 通识教育选修课: '0', 专业选修课: '0' } // 课程类别-应修学分
        let heji = 0 // 通过对“合计”关键词出现的次数进行判断，提前结束循环，解决部分班级的通识教育选修课应修学分统计不正确的情况
        for (let i = 1; i < needTable.length - 1; i++) {
          if (needTable[i][0].includes('合计')) { heji++; continue }
          if (heji === 2) break
          if (needTable[i][0].includes('类别')) continue
          else if (needTable[i][1] === '选修') need[`${needTable[i - 1][0].replace('课', '')}选修课`] = needTable[i][3]
          else if (needTable[i + 1][0] === '') need[`${needTable[i][0].replace('课', '') + needTable[i][1]}课`] = needTable[i][3]
          else if (needTable[i][0].includes('实践')) need[needTable[i][0]] = needTable[i][2]
          else need[needTable[i][0]] = needTable[i][3]
        }
        /* end */

        /* 从成绩页面获取修读情况 */
        const temD = {}
        const gradeTable = tableToList(R3.data.toString(), '#grid21344342991')
        // console.log('gradeTable', gradeTable)
        const saveName = []
        gradeTable.forEach((item, idx) => {
          if (idx === 0 || !item[10] || item[3] === '创新创业、社会实践活动') return true // 去掉课程性质为空课程
          const [grade, status] = gradeStatus(item[7])
          // console.log('gradeStatus(item[7])', gradeStatus(item[7]))

          if (saveName.includes(item[3])) { // 重复课程取最高分
            if (status === '已获') {
              temD[item[3]][0] = item[1]
              temD[item[3]][1] = grade
              temD[item[3]][4] = status
            }
            return true
          }

          temD[item[3]] = [item[0], item[7], item[5], item[4], status]
          saveName.push(item[3])
          // console.log('saveName.push(item[3])', saveName.push(item[3]))

          return true
        })
        // console.log('gradeTable', gradeTable)
        // console.log('temD', temD)
        /* end */

        /*
          1. 从培养计划中获取课程名称及课程性质，用户得到修读中课程的课程性质
          2. 统计非选修课程需要修读的学分
        */
        const nameType = {}
        let type = ''
        const tableList2 = tableToList(R1.data.toString(), '#mxh')
        // console.log('tableList2', tableList2)
        tableList2.forEach((item, idx) => {
          if (idx < 2) return true
          if (item[0] === '合计') return false
          if (item[0] === '小计') {
            if (!type.includes('专业') || !type.includes('选修')) {
              if (!need[type]) need[type] = item[5]
            }
            type = ''
            return true
          }
          if (type === '') type = item[0]
          if (!(item[3] in temD)) {
            temD[item[3]] = [getTerm(this.ctx.data.sid.slice(0, 4), Number(item[item.length - 1])), '', item[5], type, '']
          }
          nameType[item[3]] = type
          return true
        })
        // console.log('nameType', nameType)
        /* end */

        /* 从完成情况中获取修读中的课程数据，并得到其对应的课程性质 */
        const resultTable1 = tableToList(R2.data.toString(), '#chartView')
        // console.log('resultTable1', resultTable1)
        const resultTable2 = tableToList(R2.data.toString(), '#t3')
        // console.log('resultTable2', resultTable2)
        const $ = cheerio.load(R2.data.toString())
        const rows = $('.formTable').find('.darkColumn')
        // console.log('rows', rows)
        rows.each((index, e) => {
          console.log('$(e).text()', $(e).text().split('\n').map((s) => s.trim().replace(/\s/g, '')).filter((s) => s !== ''))
        })
        const processedData = [] // 创建一个新的空数组来存储处理后的数据

        rows.each((index, e) => {
          // 获取元素的文本内容，进行处理（去除换行符、空格等）
          const processedText = $(e).text().split('\n').map((s) => s.trim().replace(/\s+/g, '')).filter((s) => s !== '')
          processedData.push(processedText)
        })
        const specificValues = processedData.map((subArray) => [subArray[0], subArray[1]])
        // console.log(specificValues)
        const data = specificValues
        const updatedData = data.map((item) => {
          // 如果第一个元素包含"(所有子项至少一项满足要求)"，则删除它
          const updatedItem = item.map((str) => str.replace(/(所有子项至少一项满足要求)/, ''))
          return updatedItem
        })
        // console.log(updatedData)
        resultTable1.forEach((e) => {
          if (e[7] === '修读中') temD[e[3]] = [e[1], e[5], e[4], nameType[e[3]], e[6]]
        })
        resultTable2.forEach((e) => {
          if (e[7] === '修读中') temD[e[3]] = [e[1], e[5], e[4], '通识教育选修课', e[6]]
        })
        /* end */
        const categoriesAndCredits = updatedData
        // console.log('categoriesAndCredits', categoriesAndCredits)
        const courses = temD
        // console.log('courses', courses)
        const creditMap = new Map(categoriesAndCredits.map(([categoryWithInfo, credit]) => {
          // 提取课程性质的汉字部分（这里假设课程性质在'/'之前，并且可能包含数字或括号
          const category = categoryWithInfo.replace(/[()0-9/]/g, '').trim()// 移除数字、括号和斜杠
          // console.log('category', category)
          return [category, credit.trim()]
        }))
        // console.log('creditMap', creditMap)
        const originalArray = []
        for (const [key, value] of creditMap) {
          originalArray.push(`${key} ${value}`)
        }
        // console.log(originalArray)
        const formattedArray = originalArray.map(item => item.replace(/^[一二三四五六七八九十.]+[ ]?/, ''))
        // console.log(formattedArray)
        // 创建一个空的 Map 对象
        const courseCreditsMap = new Map()
        // 遍历 formattedArray 数组
        formattedArray.forEach(item => {
        // 使用正则表达式分割课程类型和学分
        // 假设课程类型和学分之间有空格
          const [courseType, credit] = item.split(/\s+/)// \s+ 匹配一个或多个空白字符
          // 清除学分字符串中的任何非数字字符（如果有的话
          const numericCredit = Number(credit.replace(/[^\d]/g, ''))
          // 将课程类型和学分添加到 Map 中
          // 注意：如果同一个课程类型有多个条目，后面的会覆盖前面的
          courseCreditsMap.set(courseType, numericCredit)
        })
        for (let [key, value] of courseCreditsMap) {
          console.log(`课程类型: ${key}, 学分: ${value}`)
        }
        // 遍历courses对象，追加学分
        const formattedCourses = {}
        for (const courseName in courses) {
          if (Object.prototype.hasOwnProperty.call(courses, courseName)) {
            const courseInfo = courses[courseName]
            // 假设课程性质在数组中的索引位置是固定的，这里设为3（根据实际情况调整）
            const categoryIndex = 3
            const fullCategory = courseInfo[categoryIndex]
            // 提取课程性质的汉字部分
            const category = fullCategory.replace(/[()0-9/]/g, '').trim()
            // console.log('category', category)
            // 如果creditMap中有匹配的键，则追加学分
            if (courseCreditsMap.has(category)) {
            // 假设courses[courseName]是一个数组，我们可能想要修改它或者创建一个新的包含学分的对象
            // 这里选择创建一个新的对象来保存课程信息和学分
              formattedCourses[courseName] = {
                ...courseInfo, // 复制原始课程信息（如果需要
                5: courseCreditsMap.get(category), // 追加学分
              }
            } else {
            // 如果没有找到匹配的学分，可以选择不处理或者给一个默认值
              formattedCourses[courseName] = {
                ...courseInfo,
                5: '0', // 或者null、0等
              }
            }
          }
        }
        console.log(formattedCourses)

        /* 数据准备完成，开始构造最终数据 */
        const saveType = [] // 课程性质
        const result = []
        // console.log('temD', temD)
        for (const key in formattedCourses) {
          type = formattedCourses[key][3]
          console.log('type ', type)
          if (!type) continue
          const index = saveType.indexOf(type)
          // console.log('saveType.indexOf(type)', saveType.indexOf(type))
          if (index === -1) {
            saveType.push(type)
            result.push({
              category: type,
              details: [{
                N: key,
                T: temD[key][0],
                G: temD[key][1],
                C: temD[key][2],
                S: temD[key][4],
              }],
              need: formattedCourses[key][5],
              has: temD[key][4] === '已获' ? temD[key][2] : '0',
            })
          } else {
            result[index].details.push({
              N: key,
              T: temD[key][0],
              G: temD[key][1],
              C: temD[key][2],
              S: temD[key][4],
            })
            if (temD[key][4] === '已获') result[index].has = `${Number(temD[key][2]) + Number(result[index].has)}`
          }
        }
        /* 按学期排序 */
        for (const i of result) {
          i.details.sort((a, b) => {
            if (a.T < b.T) return -1
            if (a.T > b.T) return 1
            return 0
          })
        }
        return result
      } catch (err) {
        console.log('err', err)
        throw err
      }
    }
    return []
  }

  /**
   * * 创新学分、素拓分、第二课堂分
   * @return {Array} *
   */
  async extra() {
    const Cookie = this.ctx.state.Cookie
    const apiUrl = `${this.ctx.state.baseUrl}/jsxsd/pyfa/cxxf_query`
    const res = await this.ctx.curl(apiUrl, {
      method: 'GET',
      headers: {
        Cookie,
        'Content-Type': 'application/x-www-form-urlencoded',
        'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.88 Safari/537.36',
      },
      timeout: 10000,
    })

    const header = ['学期', '项目名称', '学分', '编号', '类型', '备注'] // 列名称
    if (res.status === 200) {
      try {
        const tableList = tableToList(res.data.toString(), '#dataList')
        /* [ '序号', '学年学期', '项目编号', '学号', '姓名', '学分', '学分类型', '备注' ]; */

        const columnNeed = [1, 3, 6, 2, 7, 8] // 需要提取的列序号
        if (tableList.length === 0 || tableList[1][0] === '未查询到数据') return { table: [], header, has: '0' }

        const table = []
        let has = 0
        for (let i = 1; i < tableList.length; i++) {
          const tem = []
          columnNeed.forEach((idx) => { tem.push(tableList[i][idx]) })
          if (tem[0]) { table.push(tem) }
          has += Number(tem[2])
        }
        return { table, header, has: `${has}` }
      } catch (err) {
        console.log('err', err)
        throw err
      }
    }
    return { table: [], header, has: '0' }
  }
}
